package com.zg.autoform.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zg.autoform.service.SelectService;
import com.zg.autoform.vo.DataSelectVo;
import com.zg.autoform.web.req.*;
import com.zg.autoform.web.vo.CascadeInfoVo;
import com.zg.common.core.A;
import com.zg.common.core.C;
import com.zg.common.core.R;
import com.zg.common.core.dao.autoform.DiySelect;
import com.zg.common.core.dao.autoform.DiySelectDao;
import com.zg.common.core.dao.autoform.DiyViewSelect;
import com.zg.common.core.dao.autoform.DiyViewSelectDao;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 数据选择器服务实现类
 * @author zg
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class SelectServiceImpl implements SelectService {

    private final DiySelectDao diySelectDao;
    private final DiyViewSelectDao diyViewSelectDao;

    @Override
    public R<CascadeInfoVo> add(SelectAddReq req) {
        // 检查是否已存在
        if (diySelectDao.exists(new QueryWrapper<DiySelect>().lambda().eq(DiySelect::getFormId, req.getFormId()))) {
            return R.error("数据选择器已经存在");
        }

        DiySelect diySelect = new DiySelect();
        BeanUtil.copyProperties(req, diySelect);
        diySelect.setSearchStr(req.getName());
        diySelectDao.save(diySelect);

        // 返回创建的数据
        return R.success(buildCascadeInfoVo(diySelect));
    }

    @Override
    public R<CascadeInfoVo> update(SelectUpdateReq req) {
        DiySelect old = diySelectDao.getById(req.getId());
        A.isInDatabase(old, "数据选择器");
        BeanUtil.copyProperties(req, old, C.IGNORED_PROPERTIES);
        old.setSearchStr(req.getName());
        diySelectDao.updateById(old);

        // 返回更新后的数据
        return R.success(buildCascadeInfoVo(old));
    }

    @Override
    public R<?> delete(SelectDeleteReq req) {
        diySelectDao.removeBatchByIds(req.getIds());
        return R.success();
    }

    @Override
    public R<List<DataSelectVo>> listDataSelects(ListDataSelectsReq req) {
        List<DiySelect> list = diySelectDao.list(
            new LambdaQueryWrapper<DiySelect>()
                .ne(DiySelect::getFormId, req.getFormId())
                .orderByAsc(DiySelect::getName)
        );

        if (CollUtil.isEmpty(list)) {
            return R.success(new ArrayList<>());
        }

        List<DataSelectVo> result = list.stream()
                .map(t -> new DataSelectVo(t.getId(), t.getName(), t.getFormId()))
                .collect(Collectors.toList());
        return R.success(result);
    }

    @Override
    public R<?> viewBindSelect(ViewBindSelectReq req) {
        // 先删除原有绑定关系
        diyViewSelectDao.remove(new QueryWrapper<DiyViewSelect>().lambda().eq(DiyViewSelect::getViewId, req.getViewId()));

        // 创建新的绑定关系
        List<DiyViewSelect> list = new ArrayList<>();
        for (Long selectId : req.getSelectIds()) {
            DiyViewSelect diyViewSelect = new DiyViewSelect();
            diyViewSelect.setViewId(req.getViewId());
            diyViewSelect.setSelectId(selectId);
            list.add(diyViewSelect);
        }
        diyViewSelectDao.saveOrUpdateBatch(list);
        return R.success();
    }

    @Override
    public R<CascadeInfoVo> saveCascadeInfo(CascadeSelectReq req) {
        DiySelect diySelect = diySelectDao.getById(req.getId());
        A.isInDatabase(diySelect, "数据选择器");
        DiySelect parentSelect = diySelectDao.getById(req.getParentId());
        A.isInDatabase(parentSelect, "父级数据选择器");

        diySelect.setParentId(parentSelect.getId());
        diySelect.setParentField(req.getParentField());
        diySelect.setRelatedField(req.getRelatedField());
        diySelectDao.updateById(diySelect);

        // 返回更新后的数据
        return R.success(buildCascadeInfoVo(diySelect));
    }

    @Override
    public R<CascadeInfoVo> removeCascadeInfo(RemoveCascadeInfoReq req) {
        DiySelect diySelect = diySelectDao.getById(req.getSelectId());
        A.isInDatabase(diySelect, "数据选择器");

        diySelect.setParentId(null);
        diySelect.setParentField(null);
        diySelect.setRelatedField(null);
        diySelectDao.updateById(diySelect);

        // 返回更新后的数据
        return R.success(buildCascadeInfoVo(diySelect));
    }



    @Override
    public R<List<CascadeInfoVo>> getCascadeTree(GetCascadeTreeReq req) {
        DiySelect currentSelect = diySelectDao.getById(req.getSelectId());
        A.isInDatabase(currentSelect, "数据选择器");

        // 构建级联链路（从根节点到当前节点）
        List<DiySelect> cascadeChain = buildCascadeChain(currentSelect);
        List<CascadeInfoVo> cascadeTree = new ArrayList<>();

        // 转换为VO对象
        for (DiySelect select : cascadeChain) {
            cascadeTree.add(buildCascadeInfoVo(select));
        }

        return R.success(cascadeTree);
    }



    /**
     * 构建级联链路（从根节点到当前节点）
     */
    private List<DiySelect> buildCascadeChain(DiySelect currentSelect) {
        List<DiySelect> chain = new ArrayList<>();
        DiySelect current = currentSelect;

        // 从当前节点向上追溯到根节点
        while (current != null) {
            chain.add(0, current); // 插入到列表开头，保证顺序是从根到叶

            if (current.getParentId() != null) {
                current = diySelectDao.getById(current.getParentId());
            } else {
                current = null;
            }
        }

        return chain;
    }

    /**
     * 构建级联信息VO对象
     */
    private CascadeInfoVo buildCascadeInfoVo(DiySelect diySelect) {
        CascadeInfoVo vo = new CascadeInfoVo();
        vo.setId(diySelect.getId());
        vo.setName(diySelect.getName());
        vo.setParentId(diySelect.getParentId());
        vo.setParentField(diySelect.getParentField());
        vo.setRelatedField(diySelect.getRelatedField());

        // 设置父选择器名称
        if (diySelect.getParentId() != null) {
            DiySelect parentSelect = diySelectDao.getById(diySelect.getParentId());
            if (parentSelect != null) {
                vo.setParentName(parentSelect.getName());
            }
        }

        return vo;
    }
}
